/**
 * 
 */
package logic;

import io.IO;
import io.ImageReader;

import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.IOException;

import datamodel.huffman.tree.Tree;
import logic.huffman.HuffmanCode;
import logic.huffman.HuffmanTree;
import logic.trie.TrieCode;


/**
 * Questions (see exercise sheet for English version)
 * 
 * Frage 1: Vergleichen Sie die Dateigröße ihres mit Huffman codierten Bildes und des Orginalbildes.
 * Codieren Sie dazu jeweils die Bilder in einen BinärString (einmal normal RGB, einmal Huffman) und geben Sie diesen mit BinaryIO aus.
 * Die Methoden dazu sind: writeBinaryString, welche ihren HuffmanString bekommt; writeImageBinaryString bekommt das OrginalBild
 * Erklären Sie den Unterschied. Berechnen Sie aus der Dateigröße des Huffman- Bildes die mittlere
 * Anzahl Bits pro Pixel.
 * 
 * TODO: Die Größe der Huffman codierten Bildes ist ein wenig kleiner, als das Originalbild. 2.375 im durchschnitt
 * 
 * Frage 2: 
 * Was fällt Ihnen an den beiden decodierten Bildern auf, wie unterscheiden sich diese?
 * Erklären Sie die auftretenden Unterschiede in den beiden Bildern.
 * Die Method zum Speichern eines BufferedImage findet sich in der IO Klasse: saveImage erstellt aus ihrem decodierten BufferedImage eine png Datei.
 * 
 * TODO: Für das erste Bild werden die gelöschten Farben durch Weiß ersetzt wobei ein 1-Bit übrig bleibt, weshalb sich das ganze Bild verändert.
 * 		 Beim zweiten Bild findet er für bestimmte Farben keine Codierung und bricht deshlab beim blauen Pixel ab da dieser nicht im Baum vorhanden ist
 *
 * Frage 3:
 * Vergleichen Sie die Dateigröße des Originalbildes mit dem TrieCode- Bild (verlustfrei).
 * Warum sind beide bei unterschiedlicher Codierung identisch? Geben Sie eine Formel zur Berechnung
 * des Speicherbedarfs eines verlustfrei trie- codierten Bildes an.
 * Ziehen Sie nun auch das zweite Bild in ihren Vergleich mit ein. Aktualisieren Sie ihre Formel, sodass
 * diese auch die Stufen des Trees berücksichtigt.
 * Verwenden Sie wieder die Methode writeBinaryString aus IO um ihre codierten Bilder zu speichern.
 * 
 * Betrachten Sie nun die beiden decodierten Bilder. Erklären Sie Ihre Beobachtungen.
 * Worauf sind diese zurückzuführen?
 * 
 * TODO: Anders als beim Huffmann wird die Codierung nicht optimiert da wir die Farben auf 8-Ebenen verteilen. 
 * Speicherbedarf = (Pixel * EbenenImBaum)/ 2.
 * Die Bilder verlieren an Kontrast und werden damit auch immer kleiner.
 * 
 * 
 * Frage 4:
 * Wie erklärt sich der Unterschied im Orginalbild und dem wieder decodierten Bild?
 * 
 * TODO: dunkler, weil weniger Kontrast
 *
 * Frage 5:
 * Vergleichen Sie die Geschwindigkeit beider Suchmethoden. Geben Sie eine theoretische Erklärung für ihre Beobachtungen an.
 * 
 * TODO: Huffmann bei eintönigen Bildern schneller als beim Trie.
 * 		 Trie ist bei Bildern mit einer hohen Farbvielfalt schneller, da immer nur 8-Ebenen durchsucht werden müssen.
 * 		 Huffmanbaum-Höhe nicht genau definiert.
 */

/**
 * Interaction with the application
 * 
 * @author Jakob Karolus, Kevin Munk
 * @version 1.0
 * 
 */
public class Main {

	public static void main(String[] args) throws FileNotFoundException, IOException {
		Question1();
		Question2();
		Question3();
		Question4();
	}
	
	private static void Question1() throws FileNotFoundException, IOException {
		IO.writeImageBinaryString("Q1-original", new ImageReader("test2.png"));
		
		Tree tree = HuffmanTree.getHuffmanTree("test2.png");
		HuffmanCode code = new HuffmanCode(tree);
		
		ImageReader imageReader = new ImageReader("test2.png");
		String encryptedImage = code.encryptImage(imageReader);
		IO.writeBinaryString("Q1-huffmann", encryptedImage);
	}
	
	private static void Question2() throws FileNotFoundException, IOException {
		Tree tree = HuffmanTree.getHuffmanTree("test2.png");
		HuffmanCode code = new HuffmanCode(tree);
		
		ImageReader imageReader = new ImageReader("test2.png");
		String encryptedImage = code.encryptImage(imageReader);
		
		// Baum um eine Ebene kürzen
		code.compress(1);
		
		BufferedImage image = code.decryptImage(encryptedImage, 8, 8);
		IO.saveImage("Q2-A", image);
		
		// Bild mit gekürztem Baum codieren und decodieren
		encryptedImage = code.encryptImage(imageReader);
		image = code.decryptImage(encryptedImage, 8, 8);
		IO.saveImage("Q2-B", image);
	}
	
	private static void Question3() throws FileNotFoundException, IOException {
		TrieCode trie = new TrieCode();
		ImageReader reader = new ImageReader("test.png");
		trie.buildTrie(reader);
		
		String encryptedImageOriginal = trie.encryptImage(reader);
		IO.saveImage("Q3-decryp-org", trie.decryptImage(encryptedImageOriginal, 600, 800));
		
		// Um 3 Stufen kürzen
		trie.compress(3);
		String encryptedImageCompressed3 = trie.encryptImage(reader);
		IO.saveImage("Q3-decryp-comp3", trie.decryptImage(encryptedImageCompressed3, 600, 800));
		
		// weitere 3 Stufen entfernen
		trie.compress(3);
		String encryptedImageCompressed6 = trie.encryptImage(reader);
		IO.saveImage("Q3-decryp-comp6", trie.decryptImage(encryptedImageCompressed6, 600, 800));
		
		IO.writeImageBinaryString("Q3-original", reader);
		IO.writeBinaryString("Q3-encrypted", encryptedImageOriginal);
		IO.writeBinaryString("Q3-compressed3", encryptedImageCompressed3);
		IO.writeBinaryString("Q3-compressed6", encryptedImageCompressed6);	
	}
	
	private static void Question4() throws FileNotFoundException, IOException {
		TrieCode trie = new TrieCode();
		trie.buildTrie(new ImageReader("test.png"));
		
		String encryptedImage = trie.encryptImage(new ImageReader("test2.png"));
		BufferedImage image = trie.decryptImage(encryptedImage, 8, 8);
		IO.saveImage("Q4-test2", image);
	}

}
